package com.iflytek.jcy.supervise.clue.component.config;

import javax.servlet.MultipartConfigElement;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.List;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.util.unit.DataSize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author <a href=mailto:ktyi@iflytek.com>伊开堂</a>
 * @date 2021/6/30
 */
@Configuration
@Controller
public class AppConfig implements WebMvcConfigurer {
    @Value("${spring.servlet.multipart.max-request-size:1GB}")
    private String maxRequestSizeStr;
    @Value("${spring.servlet.multipart.max-file-size:1GB}")
    private String maxFileSizeStr;
    @Value("${spring.application.name:application}")
    private String appName;

    // 获取cpu核数, 便于创建线程池指定线程数量
    public static final int CPU_SIZE = Runtime.getRuntime().availableProcessors();

    /* java -jar 方式运行 */
    public static final boolean runByJar;
    // java -jar运行时jar包所在目录 或 开发时的工程根目录
    public static final String rootPath;

    static {
        // IDEA启动时该值为xx.xx.xxApplication, 而java -jar启动时该值为 xx.jar
        String command = System.getProperty("sun.java.command");

        // jar:file:/iflytek/server/test-1.0-SNAPSHOT/lib/test-1.0-SNAPSHOT-with-dependencies.jar!/BOOT-INF/classes!/
        // file:/Users/yikaitang/workspace/2022/untitled/target/classes/
        URL location = LogbackConfig.class.getProtectionDomain().getCodeSource().getLocation();
        String classesPath = location.toString();

        runByJar = StringUtils.endsWithIgnoreCase(command, "jar") || classesPath.startsWith("jar:");
        if (runByJar) {
            String tmp = classesPath.substring(classesPath.indexOf("/"), classesPath.indexOf(".jar"));
            rootPath = tmp.substring(0, tmp.lastIndexOf("/"));
        }
        else {
            rootPath = classesPath.substring(classesPath.indexOf("/"), classesPath.indexOf("/target"));
        }
    }

    @GetMapping("/")
    public void index(HttpServletResponse response) throws IOException {
        try (PrintWriter writer = response.getWriter()) {
            writer.write("<h1>" + appName + " is running ~~~~</h1>");
            String now = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").format(
                    LocalDateTime.now(ZoneOffset.ofHours(8)));
            writer.write("<p>" + now + "</>");
            writer.flush();
        }
    }

    /** 配置文件上传大小限制与临时文件目录 */
    @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        String tempDir = System.getProperty("java.tmp.dir");
        if (tempDir == null) {
            tempDir = "/tmp";
        }
        File tmpFile = new File(tempDir);
        if (!tmpFile.exists()) {
            tmpFile.mkdirs();
        }

        DataSize maxFileSize = DataSize.parse(maxFileSizeStr);
        DataSize maxRequestSize = DataSize.parse(maxRequestSizeStr);
        factory.setLocation(tempDir);
        factory.setMaxFileSize(maxFileSize);
        factory.setMaxRequestSize(maxRequestSize);
        return factory.createMultipartConfig();
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        SimpleModule simpleModule = new SimpleModule();
        // 序列换成Json时, 将所有的Long变成String, 因为js中得数字类型不能包括所有的java Long值
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);

        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        //builder.serializationInclusion(JsonInclude.Include.NULL);

        ObjectMapper objectMapper = builder.build();
        objectMapper.registerModule(simpleModule);
        objectMapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);// 忽略 transient 修饰的属性
        // 解决Controller返回String, ResponseBodyAdvice失效问题
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);

        // 所有的double类型返回保留三位小数
        // simpleModule.addSerializer(Double.class, CustomerDoubleSerialize.instance);
        // simpleModule.addSerializer(Double.TYPE, CustomerDoubleSerialize.instance);

        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setObjectMapper(objectMapper);
        converters.add(0, converter);
    }

}
